<template>
  <component
    ref="formRef"
    :is="is ? 'el-form' : 'div'"
    :inline="inline"
    :model="formParam"
    v-bind="formConfig"
  >
    <!-- 表单 -->
    <Form
      v-if="form"
      v-bind="props"
      @query="query"
      @reset="reset"
      @changeValue="(data) => emit('changeValue', data)"
    >
      <!-- 导出插槽 -->
      <template v-for="(value, name) in $slots" #[name]="slotData">
        <slot v-bind="slotData || {}" :name="name" />
      </template>
    </Form>
    <!-- 搜索 -->
    <Search
      v-if="search"
      v-bind="props"
      @query="query"
      @reset="reset"
      @changeValue="(data) => emit('changeValue', data)"
    >
      <!-- 导出插槽 -->
      <template v-for="(value, name) in $slots" #[name]="slotData">
        <slot v-bind="slotData || {}" :name="name" />
      </template>
    </Search>
    <!-- 中间层：信息/按钮等 -->
    <slot v-bind="{ loading }" name="info" />
    <!-- 列表 -->
    <el-form-item v-if="table" style="width: 100%; margin: 0" :label="label">
      <el-table
        ref="tableRef"
        class="form-table"
        size="small"
        style="width: 100%"
        :data="keys ? formParam[keys] : tableData.data"
        v-loading="loading"
        v-bind="$attrs"
      >
        <!-- 复选框 -->
        <el-table-column
          v-if="table.showSelect"
          :fixed="table.showFixed"
          type="selection"
          width="55px"
          align="center"
        />
        <!-- 序号 -->
        <el-table-column
          v-if="table.showIndex"
          :fixed="table.showFixed"
          type="index"
          label="序号"
          width="80px"
          align="center"
        ></el-table-column>
        <!-- 内容 -->
        <el-table-column
          v-for="item in table.propList"
          v-bind="item"
          :key="item.prop"
        >
          <!-- 需要被el-form包裹效验才可生效 -->
          <template
            v-if="item.type || item.slotForm || item.slotName || item.render"
            #default="{ row, $index: index }"
          >
            <template v-if="item.render && typeof item.render === 'function'">
              <span
                v-bind="item.renderConfig || {}"
                v-html="item.render({ item, row, index })"
              ></span>
            </template>
            <!-- 效验提示被遮挡请添加全局样式 -->
            <!-- .el-form-item {margin-bottom: 18px !important;} -->
            <!-- 此处不能使用v-else-if，会导致效验索引-1，一直存在效验 -->
            <el-form-item
              v-if="item.type"
              style="width: 100%"
              :prop="keys ? [keys, index, item.prop] : null"
              :rules="
                item.rules
                  ? findConfig(item.rules, formConfig)
                  : [
                      {
                        required:
                          typeof item.required === 'function'
                            ? item.required({ row })
                            : findConfig(item.required, formConfig),
                        message:
                          item.m ||
                          item.message ||
                          `${rulesMessage[item.type]}${item.label}`,
                      },
                    ]
              "
            >
              <!-- 框架 -->
              <Frames
                v-bind="props"
                :formParam="row"
                :data="{ ...item, row, index }"
                @changeValue="(data) => emit('changeValue', data)"
              />
            </el-form-item>
            <!-- 自定义插槽：form标签包裹，保持页面完整性 -->
            <el-form-item
              v-else-if="item.slotForm"
              style="display: inline-block"
            >
              <slot v-bind="{ row, item, index }" :name="item.slotForm">
                {{ item.prop ? row[item.prop] : "" }}
              </slot>
            </el-form-item>
            <!-- 自定义插槽 -->
            <slot
              v-else-if="item.slotName"
              v-bind="{ row, item, index }"
              :name="item.slotName"
            >
              {{ item.prop ? row[item.prop] : "" }}
            </slot>
          </template>
          <!-- el-table-column：本身插槽 -->
          <template v-for="(value, name) in $slots" #[name]="slotData">
            <slot v-bind="slotData || {}" :name="name" />
          </template>
        </el-table-column>
        <!-- el-table：本身插槽 -->
        <template v-for="(value, name) in $slots" #[name]="slotData">
          <slot v-bind="slotData || {}" :name="name" />
        </template>
      </el-table>
    </el-form-item>
    <!-- 分页 -->
    <template v-if="table && table.showFooter">
      <div class="pagination">
        <el-pagination
          v-model:page-size="apiParam.size"
          v-model:current-page="apiParam.current"
          :page-sizes="[10, 20, 50, 100]"
          :total="tableData?.total"
          background
          layout="total, sizes, prev, pager, next, jumper"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
        >
        </el-pagination>
      </div>
    </template>
  </component>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { propsConfig, findConfig, rulesMessage } from "./utils/index.js";
import Form from "./form.vue";
import Search from "./search.vue";
import Frames from "./utils/index.vue";

/** 项目列表添加行/审批居多，可使用此封装组件，分页也可 */
const emit = defineEmits(["changeValue"]);
const props = defineProps({
  /**
   * 是否内嵌 a-form 表单
   * is：true表示内嵌a-form标签
   * is：false则使用需要在最外层父组件使用 a-form标签包裹组件，因为在使用validate()等方法复用性高
   */
  is: { type: Boolean, default: true },
  // 表格列的配置
  table: { type: Object, default: null },
  // 列表字段，用于效验，新增删除
  keys: { type: String, default: null },
  // 接口
  apiFn: { type: Function, default: null },
  // 在父组件使用xxRef.value.setFn的时候，传递一个函数替换掉getFn方法
  setFn: { type: Function, default: null },
  // 传递默认值 default: () => ({ current: 1, size: 10 }),
  apiParam: { type: Object, default: null },
  // 是否内联
  inline: { type: Boolean, default: true },
  // table搜索
  form: { type: Array, default: null },
  search: { type: Array, default: null },
  // table表格label
  label: { type: String, default: null },
  // form表单是否需要label
  isLabel: { type: Boolean, default: true },
  ...propsConfig,
});

// ref
const formRef = ref(null);

/** 分页 */
const handleSizeChange = (val) => refresh();
const handleCurrentChange = (val) => refresh();
/**
 * 修改apiFn父组件传递的接口，并暴露给父组件
 * 防止传递默认参数失效时使用调用setFn函数修改
 */
const setFn = (newFn, params) => getFn(newFn, params);
// 获取接口列表
const loading = ref(false);
const tableData = ref({ data: [], total: 0 }); // 列表数据
const getFn = async (newFn, params = {}) => {
  const { keys, apiFn, apiParam, formParam } = props;
  if (!apiFn && !newFn) return;
  const fn = apiFn || newFn;
  console.log(
    { ...formParam, ...apiParam, ...params },
    "列表参数：搜索“getFn”删除打印结果"
  );
  loading.value = true;
  try {
    const res = await fn({ ...formParam, ...apiParam, ...params });
    const data = res?.data || res || [];
    if (keys) {
      formParam[keys] = data;
      return;
    }
    tableData.value = { data, total: res?.total || 0 };
    /**
     * 根据自己数据结构调整
    if (keys) {
			formParam.value[keys] = res.records ? res.records : res || []
			return
		}
		tableData.value = res.records ? res.records : res || []
    paginationConfig.total = total;
    */
  } catch (error) {
    console.error("请求失败:", error);
  } finally {
    loading.value = false;
  }
};

// 更新传递默认值
const updateFormParams = (data) => Object.assign(props.apiParam, data);

// 查询
const query = (callback) => {
  // 如果需要每次查询重置都返回第一页则打开
  // updateFormParams({ current: 1 });
  callback && callback();
  refresh();
};
// 重置
const reset = (callback) => {
  const { formParam } = props;
  for (const key in formParam) {
    formParam[key] = undefined;
  }
  callback && callback();
  // 如果不需要重置返回第一页，可以默认调用refresh方法
  query();
};
// 刷新
const refresh = (callback) => {
  callback && callback();
  (props.setFn && props.setFn()) || getFn();
};

onMounted(() => {
  // 不建议默认refresh，获取其他接口params的时候会导致接口已经调用，参数没获取的情况
  getFn();
});

defineExpose({
  validate: () => formRef.value.validate(),
  resetFields: () => formRef.value.resetFields(),
  setFn,
  refresh,
  query,
  reset,
});
</script>

<style scoped lang="scss">
.pagination {
  margin-top: 20px;
}
:deep(.el-pagination) {
  justify-content: flex-end;
}

:deep(.form-table) {
  .el-form-item__content {
    margin-left: 0 !important;
  }
}
</style>
